初學 Dart 如果你常常被一些魔法般的程式碼困惑,很可能是沒有深入理解模式的概念。模式(Pattern)是 Dart 3.0 引入的一個重要特性,模式 pattern 的概念主要是涉及「比對」match 和「解構」destructure 。準確的說就是可以實現「比對」或「解構」的語法,類似於語句 statement 和表達式 expression。可以把模式想成是一個資料的模板,具備特定結構,我們可以用來比對是否符合結構,進一步解構取得值。
許多新語言都支援類似模式的概念,例如 Swift ,Kotlin 的解構和
when。粗略來說我們可以把模式概念理解為一種 switch-case case 條件的進化版。
模式在 Dart 中主要用於兩個目的:比對和解構。
具體來說,模式本身有很多類型可以協助我們比對各種類型的資料:
swtich 比對某個值例如 null、true、'abc'
var x
['a' || 'b', var c] ,匹配一個值是一有兩個元素的列表,第一個元素需要是 a 或 b,而 var c 則是變數模式,任何值可以綁定到變數 c。{"name": String name } 匹配特定鍵值對Person(:name),也可以進一步比對屬性。物件模式看起來像是預設建構子,甚至該類別沒有預設建構子也是一樣的撰寫方式,更多例子如 String() ,int()
_  任何值都匹配(1, int y) ,一個常數和變數型別模式組合而成的 Record從列表模式的範例我們知道模式是可以和邏輯運算子搭配使用的,包含 && , || 以及 () 類似表達式。如此可以增加比對匹配的複雜性和靈活性
根據模式出現的位置提供比對或解構的功能:
var nums = [1 ,2 ,3];
var [a, b, c] = nums;
switch (list) {
  case ['a' || 'b', var c]:
    print(c);
}
接著,我們進一步瞭解模式可能出現的位置:
for 和 for-in 迴圈if-case 和 swtich-case
// 變數宣告
var (a, [b, c]) = ('A', [1, 2]); // 模式變數須使用 `var` 或 `final` 開頭。
(b, a) = (a, b); // 交換
// switch
// 模式在 case 中的解構值會變成區域變數,只限於該 case 範圍內
switch (obj) {
  case 1:
  // 如果 obj 大於等於 2 小於等於 5
  case >= 2 && <= 5:
  // 如果 obj 是一個 2 個元素的 Record
  case (var x, var y):
}
// 邏輯或模式
var isOdd = switch (n) {
    1 || 3 || 5 => true,
    _ => false
}
// 搭配 when
switch (shape) {
  case Square(size: var s) || Circle(size: var s) when s > 0:
    //
}
switch (pair) {
  case (int a, int b) when a > b:
    // 
}
在某些情況下,模式匹配可能失敗,但不會導致錯誤,而是繼續執行下一個選項。這種情況稱為 Refutable context。例如,switch 語句和 if-case 語句中的模式就是在 Refutable context 中。
User? fromJson(Map<String, Object?> data) => switch(data) {
  {'username': String name, 'age': int age} => User(
    username: name,
    age: age,
  ),
  _ => null,
};
bool isUnitCircle(Object? data) {
  if (data case Circle(radius: var rad) when rad ==1) {
   return true;
  }
  return false;
}
有了模式的概念很多東西就比較容易理解。例如 if-case 的 case 我們可以想成原本只能用 == 、!= 等邏輯運算子,現在可以通過 case 直接使用模式比對
// 如果沒有 case
if (pair is List && 
    pair.length == 2 && 
    pair[0] is int && 
    pair[1] is int) {
  return Point(pair[0] as int, pair[1] as int);
}
// case 版本
if (pair case [int x, int y]) return Point(x, y);